import os
from os import path
from pydantic_settings import BaseSettings
from typing import Literal, Optional
from functools import lru_cache
from dotenv import load_dotenv
from envcrypto import decrypt, encrypt
from enum import Enum

# 项目根目录
ROOT_PATH: str = os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__))))


class BusinessType(Enum):
    """
    业务操作类型

    OTHER: 其它
    INSERT: 新增
    UPDATE: 修改
    DELETE: 删除
    EDIT: 编辑
    GET: 获取
    """

    OTHER = 0
    INSERT = 1
    UPDATE = 2
    DELETE = 3
    EDIT = 4
    GET = 5


class BaseAppSettings(BaseSettings):

    # Uvicorn
    UVICORN_HOST: str = '127.0.0.1'
    UVICORN_PORT: int = 8089
    UVICORN_RELOAD: bool = False

    # 加密KEY
    SECRET_KEY: str = "w*{s,=h:Ai!UaL?+f~GYE|z)p,.T6FFvGxM4DVtK"
    DEBUG: bool = True
    APP_ENV: Literal['dev', 'prod'] = 'dev'
    APP_NAME: str = 'FastAPI-Pro'

    # 静态资源目录
    STATIC_DIR: str = os.path.join(ROOT_PATH, "static")

    # 是否开启API文档
    OPEN_DOCS: bool = True

    # 日志级别
    LOG_DEFAULT_LEVEL: str = 'INFO'
    LOG_LEVEL: str = 'INFO'
    LOG_ROTATION: str = '100 MB'
    LOG_FORMAT: str = '<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | ' \
                      '<level>{level}</level> | ' \
                      '<cyan>{name}</cyan>.<cyan>{function}</cyan>:<cyan>{line}</cyan> | ' \
                      '<level>{message}</level>'
    # 是否记录请求头和请求体(JSON)
    LOG_API_DETAILS: bool = True
    # 默认日志路径, 直接使用 logger.warning('...')
    LOG_DEFAULT_PATH: str = path.join(ROOT_PATH, "logs")
    # 管理台日志路径
    ADMIN_LOG_PATH: str = path.join(ROOT_PATH, "logs/admin")
    # API日志路径
    API_LOG_PATH: str = path.join(ROOT_PATH, "logs/api")
    # Log
    LOG_DEFAULT_FILENAME: str = 'app.log'
    LOG_STDOUT_FILENAME: str = 'access.log'
    LOG_STDERR_FILENAME: str = 'error.log'

    # 是否开启跨域
    MIDDLEWARE_CORS: bool = True
    # 是否压缩
    MIDDLEWARE_GZIP: bool = True
    # 是否开启访问日志
    MIDDLEWARE_ACCESS: bool = True
    # 允许跨域的域名
    MIDDLEWARE_CORS_ALLOW_ORIGINS: list = ['*']
    # 允许跨域的方法
    MIDDLEWARE_CORS_ALLOW_METHODS: list = ['*']
    # 允许跨域的Headers
    MIDDLEWARE_CORS_ALLOW_HEADERS: list = ['*']


class DataBaseSettings(BaseSettings):
    """
    数据库配置
    """

    OPEN_MYSQL: bool = True  # 是否开启 MYSQL
    ASYNC_DATABASE_URI: str = "mysql+aiomysql://root:123456@127.0.0.1:3306/base_api?charset=utf8mb4"
    DB_ECHO: bool = True
    MAX_OVERFLOW: int = 10
    POOL_SIZE: int = 50
    POOL_RECYCLE: int = 3600
    POOL_TIMEOUT: int = 30


class MONGODBSettings(BaseSettings):
    """
    MONGODB配置
    """

    OPEN_MONGODB: bool = False  # 是否开启 MONGODB
    MONGODB_URL: Optional[str] = None
    MONGODB_DB: Optional[str] = None
    MONGODB_COLLECTION: Optional[str] = None


class JWTSettings(BaseSettings):
    """
    JWT token
    """
    # 加密方式
    ALGORITHM: str = "HS256"
    # 管理系统token过期时间
    ADMIN_ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7
    # 前端token 过期时间
    API_ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7


class RedisSettings(BaseSettings):
    """
    Redis配置
    """
    OPEN_REDIS: bool = True  # 是否开启REDIS
    REDIS_URL: str = "redis://127.0.0.1:6379/0"
    MAX_CONNECTIONS: int = 1000


class UploadSettings(BaseSettings):
    """
    上传配置
    """

    UPLOAD_PATH: str = 'static/uploads'
    DEFAULT_ALLOWED_EXTENSION: list = [
        # 图片
        'bmp',
        'gif',
        'jpg',
        'jpeg',
        'png',
    ]


class SchedulerSettings(BaseSettings):
    """
    定时任务配置
    """
    OPEN_TASK: bool = False
    SCHEDULER_TASK_CONFIG: dict = {
        "SCHEDULER_TIMEZONE": 'Asia/Shanghai',
        "JOBS": [
            {
                'id': 'test123',
                'func': 'scheduler_task.task:test123',
                'trigger': 'interval',
                'seconds': 10
                # 'next_run_time': datetime.now() + timedelta(seconds=6),
            },
        ]
    }


class GetConfig:
    """
    获取配置
    """

    def __init__(self):
        # 读取运行环境
        run_env = os.environ.get('APP_ENV', '')
        # 运行环境未指定时默认加载.env.dev
        env_file = '.env.dev'
        # 运行环境不为空时按命令行参数加载对应.env文件
        if run_env != '':
            env_file = f'.env.{run_env}'
        # 加载配置
        load_dotenv(os.path.join(ROOT_PATH, env_file))
        self.app_config = self.get_app_config()

    def parse_settings(self, cls):
        """解码加密配置项"""
        key = getattr(self.app_config, 'SECRET_KEY')
        debug = getattr(self.app_config, 'DEBUG')
        attributes = list(cls.__fields__.keys())
        for attr_name in attributes:
            attr_value = getattr(cls, attr_name)
            # 以 E.. 开头的变量属于加密链接, 需要解密后使用
            v = str(attr_value)
            if v.startswith('E..'):
                attr_value = decrypt(v[3:], key)
                attr_value is None and print(f'settings.{attr_name} is None')
                setattr(cls, attr_name, attr_value)
            debug and print('{} = {}'.format(attr_name, attr_value))

    def encrypt_setting(self, data):
        """
        加密配置项
        :param data:
        :return:
        """
        return f"E..{encrypt(data, self.app_config.SECRET_KEY)}"

    @lru_cache()
    def get_app_config(self):
        """
        获取应用配置
        """
        # 实例化应用配置模型
        return BaseAppSettings()

    @lru_cache()
    def get_database_config(self):
        """
        获取数据库配置
        """
        # 实例化数据库配置模型
        db_conf = DataBaseSettings()
        self.parse_settings(db_conf)
        return db_conf

    @lru_cache()
    def get_mongodb_config(self):
        """
        获取MONGODB配置
        """
        mongodb_conf = MONGODBSettings()
        self.parse_settings(mongodb_conf)
        return mongodb_conf

    @lru_cache()
    def get_jwt_config(self):
        """
        获取JWT配置
        """
        jwt_conf = JWTSettings()
        self.parse_settings(jwt_conf)
        return jwt_conf

    @lru_cache()
    def get_redis_config(self):
        """
        获取Redis配置
        """
        # 实例化Redis配置模型
        redis_conf = RedisSettings()
        self.parse_settings(redis_conf)
        return redis_conf

    @lru_cache()
    def get_upload_config(self):
        """
        获取数据库配置
        """
        # 实例上传配置
        upload_conf = UploadSettings()
        self.parse_settings(upload_conf)

        # 初始化上传目录
        upload_path = os.path.join(ROOT_PATH, upload_conf.UPLOAD_PATH)
        if not os.path.exists(upload_path):
            os.makedirs(upload_path)
        return upload_conf

    @lru_cache()
    def get_scheduler_config(self):
        """
        获取定时任务配置
        """
        # 实例化Redis配置模型
        scheduler_conf = SchedulerSettings()
        self.parse_settings(scheduler_conf)
        return scheduler_conf


get_config = GetConfig()
app_config = get_config.get_app_config()
mysql_config = get_config.get_database_config()
mongodb_config = get_config.get_mongodb_config()
jwt_config = get_config.get_jwt_config()
redis_config = get_config.get_redis_config()
upload_config = get_config.get_upload_config()
scheduler_config = get_config.get_scheduler_config()


